﻿using System.Collections.Generic;
using System;
using System.Runtime.Serialization;
using System.Diagnostics; 

namespace Titan
{
    [KnownType(typeof(ConditionItem))]
    [DataContract]
    [DebuggerDisplay("Count = {Count} Relation={ConditionRelation}")]
    public class ConditionCollection : IConditionCollection
    {
        [DataMember]
        private List<IConditionExpression> Items;
        public ConditionCollection()
        {
            this.Items = new List<IConditionExpression>();
            ConditionRelation = ConditionRelation.And;
        }
        public ConditionCollection(int capcity)
        {
            this.Items = new List<IConditionExpression>(capcity);
            ConditionRelation = ConditionRelation.And;
        }

        [DataMember]
        public ConditionRelation ConditionRelation { get; set; }


        public void Add(IConditionExpression conditionExpression)
        {
            if (conditionExpression is ConditionItem)
            {
                Items.Add(conditionExpression);
            }
            else
            {
                IConditionCollection conditionCollection = (IConditionCollection)conditionExpression;
                if (ConditionRelation == ConditionRelation.And)
                {
                    if (conditionCollection.ConditionRelation == ConditionRelation.And)
                    {
                        foreach (IConditionExpression item in conditionCollection)
                        {
                            Add(item);
                        }
                    }
                    else
                    {
                        Items.Add(conditionCollection);
                    }
                }
                else
                {
                    if (conditionCollection.ConditionRelation == ConditionRelation.Or)
                    {
                        foreach (IConditionExpression item in conditionCollection)
                        {
                            Add(item);
                        }
                    }
                    else
                    {
                        Items.Add(conditionCollection);
                    }
                }
            }
        }

        public void Add(string propertyName, ConditionOperator conditionOperator, object conditionValue)
        {
            Add(new ConditionItem(propertyName, conditionOperator, conditionValue));
        }

        public void Add(string propertyName,GroupFunction groupFunction, ConditionOperator conditionOperator, object conditionValue)
        {
            Add(new ConditionItem(propertyName, groupFunction,conditionOperator, conditionValue));
        }



        private IConditionCollection Copy()
        {
            ConditionCollection cs = new ConditionCollection(Items.Count);
            cs.ConditionRelation = this.ConditionRelation;
            foreach (IConditionExpression conditionExpression in this)
            {
                cs.Add(conditionExpression);
            }
            return cs;
        }
        public void Not()
        {
            this.ConditionRelation = ConditionRelation == ConditionRelation.And ? ConditionRelation.Or : ConditionRelation.And;
            foreach (IConditionExpression item in this)
            {
                item.Not();
            }
        }
        public IConditionExpression And(IConditionExpression conditionExpression)
        {
            if (ConditionRelation == ConditionRelation.And)
            {
                if (conditionExpression is IConditionItem)
                {
                    this.Add(conditionExpression);
                }
                else
                {
                    IConditionCollection conditionCollection = (IConditionCollection)conditionExpression;
                    if (conditionCollection.ConditionRelation == ConditionRelation.And)
                    {
                        foreach (IConditionExpression item in conditionCollection)
                        {
                            this.Add(item);
                        }
                    }
                    else
                    {
                        this.Add(conditionCollection);
                    }
                }
            }
            else
            {
                IConditionCollection cs = Copy();
                Items.Clear();
                this.Add(cs);
                this.ConditionRelation = ConditionRelation.And;

                if (conditionExpression is IConditionItem)
                {
                    this.Add(conditionExpression);
                }
                else
                {
                    IConditionCollection conditionCollection = (IConditionCollection)conditionExpression;
                    if (conditionCollection.ConditionRelation == ConditionRelation.And)
                    {
                        foreach (IConditionExpression item in conditionCollection)
                        {
                            this.Add(item);
                        }
                    }
                    else
                    {
                        this.Add(conditionCollection);
                    }
                }
            }
            return this;
        }
        public IConditionExpression Or(IConditionExpression conditionExpression)
        {
            if (ConditionRelation == ConditionRelation.Or)
            {
                if (conditionExpression is IConditionItem)
                {
                    this.Add(conditionExpression);
                }
                else
                {
                    IConditionCollection conditionCollection = (IConditionCollection)conditionExpression;
                    if (conditionCollection.ConditionRelation == ConditionRelation.Or)
                    {
                        foreach (IConditionExpression item in conditionCollection)
                        {
                            this.Add(item);
                        }
                    }
                    else
                    {
                        this.Add(conditionCollection);
                    }
                }
            }
            else
            {
                IConditionCollection cs = Copy();
                Items.Clear();
                this.Add(cs);
                this.ConditionRelation = ConditionRelation.Or;

                if (conditionExpression is IConditionItem)
                {
                    this.Add(conditionExpression);
                }
                else
                {
                    IConditionCollection conditionCollection = (IConditionCollection)conditionExpression;
                    if (conditionCollection.ConditionRelation == ConditionRelation.Or)
                    {
                        foreach (IConditionExpression item in conditionCollection)
                        {
                            this.Add(item);
                        }
                    }
                    else
                    {
                        this.Add(conditionCollection);
                    }
                }
            }
            return this;
        }



        #region overload operator
        public static IConditionExpression operator &(ConditionCollection conditionCollection, IConditionExpression value)
        {
            return conditionCollection.And(value);
        }
        public static IConditionExpression operator |(ConditionCollection conditionCollection, IConditionExpression value)
        {
            return conditionCollection.Or(value);
        }
        #endregion


        #region List Interface
        public int IndexOf(IConditionExpression item)
        {
            return Items.IndexOf(item);
        }

        public void Insert(int index, IConditionExpression item)
        {
            Items.Insert(index, item);
        }

        public void RemoveAt(int index)
        {
            Items.RemoveAt(index);
        }

        public IConditionExpression this[int index]
        {
            get
            {
                return Items[index];
            }
            set
            {
                Items[index] = value;
            }
        }


        public void Clear()
        {
            Items.Clear();
        }

        public bool Contains(IConditionExpression item)
        {
            return Items.Contains(item);
        }

        public void CopyTo(IConditionExpression[] array, int arrayIndex)
        {
            Items.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return Items.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(IConditionExpression item)
        {
            return Items.Remove(item);
        }

        public IEnumerator<IConditionExpression> GetEnumerator()
        {
            return Items.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return Items.GetEnumerator();
        }
        #endregion
    }
}
